package cz.uhk.max.matrix.impl;

import cz.uhk.max.matrix.Col;
import cz.uhk.max.matrix.Matrix;
import cz.uhk.max.matrix.Row;

public class Equation {
	private Matrix A;
	private Matrix B;
	private MatrixDao dao;
	private Long infinite;

	public Equation (Matrix A, Matrix B, Long infinite){
		//matice A a B musí mít stejný počet řádků a sloupců
		this.A = new Matrix(A);
		this.B = new Matrix(B);
		dao = new MatrixDao();
		this.setInfinite(infinite);
	}
	
	public Matrix returnXMax(){
		// metoda vraci maximalni x, které vyhovuje řešení rovnice A*x=B*x v
		// max-min algebře
		Matrix candidateForX = new Matrix(A.getColsCount(), 1);
		Matrix candidateForXLast = new Matrix(A.getColsCount(), 1);
		// na začátku je nastavena hodnota candidáta na x nekonečno
		for (int i = 0; i < candidateForX.getRowsCount(); i++) {
			candidateForX.setCol(i, 0, this.infinite);
		}

		candidateForX = findXCandidateFromAllRow(candidateForX);
		//candidateForXLast = new Matrix(candidateForX);
		Boolean same = false;
		while (same == false) {
			candidateForXLast = new Matrix(candidateForX);
			//nalezne se maximální kandidát metodou:
			//zjisti kandidáta pro řádek
			//pokud zjišťuješ kandidáta pro další řádek, bez v úvahu max xi
			//z předchozího řádku
			//pokud dojde k upřesnění kandidáta na maximální x,
			//vypočítej znovu tohoto kandidáta
			candidateForX = findXCandidateFromAllRow(candidateForX);
			same = dao.isSame(candidateForX, candidateForXLast);
//			System.out.println("candidate For X: "); candidateForX.print();
//			System.out.println("candidate For XLast: "); candidateForXLast.print();
//			System.out.println("jsou stejne? " + same);
		}

//		System.out.println("jsou stejne?"
//				+ dao.isSame(candidateForX, candidateForXLast));

		return candidateForX;
	}
	
	public Matrix findXCandidateFromAllRow(Matrix candidate) {
		Matrix candidateForX = new Matrix(candidate);
		Row aTemp = new Row();
		Row bTemp = new Row();

		for (int i = 0; i < A.getRowsCount(); i++) {
			aTemp = dao.multiRowWithMatrixReturnRow(A.getRows().get(i),
					candidateForX);
			bTemp = dao.multiRowWithMatrixReturnRow(B.getRows().get(i),
					candidateForX);
			candidateForX = findXcandidate(aTemp, bTemp, candidateForX);
			aTemp = null;
			bTemp = null;
		}
		return candidateForX;
	}
	
	public Matrix findXcandidate(Row rowA, Row rowB, Matrix candidateForX){
		//pro řádek (row) se porovnají matice A a matice B
		//nejprve se zjistí, která matice obsahuje v řádku vyšší číslo
		//matice x odpovida hodnote matice ve vstupnim parametru
		Col maxA = new Col();
		Col maxB = new Col();
		Matrix xCandidate = new Matrix(candidateForX);
		maxA = dao.maximum(rowA.getCols());
		maxB = dao.maximum(rowB.getCols());

		if (maxA.getValue() > maxB.getValue()){
			//System.out.println("max A:" + maxA.getValue() + "max B: " + maxB.getValue());
			return xCandidate(rowA, rowB, maxB.getValue(), xCandidate);
		} else
		{
			return xCandidate(rowB, rowA, maxA.getValue(), xCandidate);
		}
		}
	
	public Matrix xCandidate(Row vetsiMatice, Row mensiMatice, Long maxMensiMatice, Matrix xCan) {
		Matrix xCandidate = new Matrix (xCan);
		//hodnota xCandidate se zmensi tehdy, pokud prvek v i-tem sloupci
		//ve vetsi matici je vetsi nez maximum z mensi matice
		for (int i = 0; i < vetsiMatice.getColsCount(); i++) {
			if (vetsiMatice.getCols().get(i).getValue() > maxMensiMatice) {
				xCandidate.setCol(i, 0, maxMensiMatice);
			}
		}
		return xCandidate;
	}
	
	public Matrix getA() {
		return A;
	}

	public void setA(Matrix a) {
		A = a;
	}

	public Matrix getB() {
		return B;
	}

	public void setB(Matrix b) {
		B = b;
	}

	public MatrixDao getDao() {
		return dao;
	}

	public void setDao(MatrixDao dao) {
		this.dao = dao;
	}

	public Long getInfinite() {
		return infinite;
	}

	public void setInfinite(Long infinite) {
		this.infinite = infinite;
	}


}
